package io.dropwizard.jersey.filter; import java.io.IOException; import java.util.Random; import java.util.UUID; import java.util.concurrent.ThreadLocalRandom; import javax.annotation.Priority; import javax.ws.rs.Priorities; import javax.ws.rs.container.ContainerRequestContext; import javax.ws.rs.container.ContainerResponseContext; import javax.ws.rs.container.ContainerResponseFilter; import javax.ws.rs.ext.Provider; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.base.Strings; /** * This class adds a "X-Request-Id" HTTP response header and logs the following * information: request method, request path, request ID, response status, * response length (or -1 if not known). * * @see https://devcenter.heroku.com/articles/http-request-id */ @Provider @Priority(Priorities.USER) public class RequestIdFilter implements ContainerResponseFilter { private static final Logger LOGGER = LoggerFactory.getLogger(RequestIdFilter.class); private static final String REQUEST_ID = "X-Request-Id"; @Override public void filter(final ContainerRequestContext request, final ContainerResponseContext response) throws IOException { String id = request.getHeaderString(REQUEST_ID); if (Strings.isNullOrEmpty(id)) { id = generateRandomUuid().toString(); } LOGGER.trace("method={} path={} request_id={} status={} length={}", request.getMethod(), request.getUriInfo().getPath(), id, response.getStatus(), response.getLength()); response.getHeaders().putSingle(REQUEST_ID, id); } /** * Generate a random UUID v4 that will perform reasonably when used by * multiple threads under load. * * @see https://github.com/Netflix/netflix-commons/blob/v0.3.0/netflix-commons-util/src/main/java/com/netflix/util/concurrent/ConcurrentUUIDFactory.java * @return random UUID */ private static UUID generateRandomUuid() { final Random rnd = ThreadLocalRandom.current(); long mostSig = rnd.nextLong(); long leastSig = rnd.nextLong(); // Identify this as a version 4 UUID, that is one based on a random value. mostSig &= 0xffffffffffff0fffL; mostSig |= 0x0000000000004000L; // Set the variant identifier as specified for version 4 UUID values. The two // high order bits of the lower word are required to be one and zero, respectively. leastSig &= 0x3fffffffffffffffL; leastSig |= 0x8000000000000000L; return new UUID(mostSig, leastSig); } }